home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Net / SmartIRC.php < prev    next >
Encoding:
PHP Script  |  2005-07-07  |  75.8 KB  |  2,553 lines

  1. <?php
  2. /**
  3.  * $Id: SmartIRC.php,v 1.54.2.14 2005/05/27 23:40:09 meebey Exp $
  4.  * $Revision: 1.54.2.14 $
  5.  * $Author: meebey $
  6.  * $Date: 2005/05/27 23:40:09 $
  7.  *
  8.  * Net_SmartIRC
  9.  * This is a PHP class for communication with IRC networks,
  10.  * which conforms to the RFC 2812 (IRC protocol).
  11.  * It's an API that handles all IRC protocol messages.
  12.  * This class is designed for creating IRC bots, chats and show irc related info on webpages.
  13.  *
  14.  * Documenation, a HOWTO and examples are in SmartIRC included.
  15.  *
  16.  * Here you will find a service bot which I am also developing
  17.  * <http://cvs.meebey.net/atbs> and <http://cvs.meebey.net/phpbitch>
  18.  * Latest versions of Net_SmartIRC you will find on the project homepage
  19.  * or get it through PEAR since SmartIRC is an official PEAR package.
  20.  * See <http://pear.php.net/Net_SmartIRC>.
  21.  *
  22.  * Official Projet Homepage: <http://sf.net/projects/phpsmartirc>
  23.  *
  24.  * Net_SmartIRC conforms to RFC 2812 (Internet Relay Chat: Client Protocol)
  25.  * 
  26.  * Copyright (c) 2002-2003 Mirco 'meebey' Bauer <meebey@meebey.net> <http://www.meebey.net>
  27.  * 
  28.  * Full LGPL License: <http://www.gnu.org/licenses/lgpl.txt>
  29.  * 
  30.  * This library is free software; you can redistribute it and/or
  31.  * modify it under the terms of the GNU Lesser General Public
  32.  * License as published by the Free Software Foundation; either
  33.  * version 2.1 of the License, or (at your option) any later version.
  34.  *
  35.  * This library is distributed in the hope that it will be useful,
  36.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  37.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  38.  * Lesser General Public License for more details.
  39.  *
  40.  * You should have received a copy of the GNU Lesser General Public
  41.  * License along with this library; if not, write to the Free Software
  42.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  43.  *
  44.  */
  45. // ------- PHP code ----------
  46. include_once('SmartIRC/defines.php');
  47. include_once('SmartIRC/irccommands.php');
  48. include_once('SmartIRC/messagehandler.php');
  49. define('SMARTIRC_VERSION', '1.0.0 ($Revision: 1.54.2.14 $)');
  50. define('SMARTIRC_VERSIONSTRING', 'Net_SmartIRC '.SMARTIRC_VERSION);
  51.  
  52. /**
  53.  * main SmartIRC class
  54.  *
  55.  * @package Net_SmartIRC
  56.  * @version 0.5.5
  57.  * @author Mirco 'meebey' Bauer <mail@meebey.net>
  58.  * @access public
  59.  */
  60. class Net_SmartIRC_base
  61. {
  62.     /**
  63.      * @var resource
  64.      * @access private
  65.      */
  66.     var $_socket;
  67.     
  68.     /**
  69.      * @var string
  70.      * @access private
  71.      */
  72.     var $_address;
  73.     
  74.     /**
  75.      * @var integer
  76.      * @access private
  77.      */
  78.     var $_port;
  79.     
  80.     /**
  81.      * @var string
  82.      * @access private
  83.      */
  84.     var $_nick;
  85.     
  86.     /**
  87.      * @var string
  88.      * @access private
  89.      */
  90.     var $_username;
  91.     
  92.     /**
  93.      * @var string
  94.      * @access private
  95.      */
  96.     var $_realname;
  97.     
  98.     /**
  99.      * @var string
  100.      * @access private
  101.      */
  102.     var $_usermode;
  103.     
  104.     /**
  105.      * @var string
  106.      * @access private
  107.      */
  108.     var $_password;
  109.     
  110.     /**
  111.      * @var boolean
  112.      * @access private
  113.      */
  114.     var $_state = false;
  115.     
  116.     /**
  117.      * @var array
  118.      * @access private
  119.      */
  120.     var $_actionhandler = array();
  121.     
  122.     /**
  123.      * @var array
  124.      * @access private
  125.      */
  126.     var $_timehandler = array();
  127.     
  128.     /**
  129.      * @var integer
  130.      * @access private
  131.      */
  132.     var $_debug = SMARTIRC_DEBUG_NOTICE;
  133.     
  134.     /**
  135.      * @var array
  136.      * @access private
  137.      */
  138.     var $_messagebuffer = array();
  139.     
  140.     /**
  141.      * @var integer
  142.      * @access private
  143.      */
  144.     var $_messagebuffersize;
  145.     
  146.     /**
  147.      * @var boolean
  148.      * @access private
  149.      */
  150.     var $_usesockets = false;
  151.     
  152.     /**
  153.      * @var integer
  154.      * @access private
  155.      */
  156.     var $_receivedelay = 100;
  157.     
  158.     /**
  159.      * @var integer
  160.      * @access private
  161.      */
  162.     var $_senddelay = 250;
  163.     
  164.     /**
  165.      * @var integer
  166.      * @access private
  167.      */
  168.     var $_logdestination = SMARTIRC_STDOUT;
  169.     
  170.     /**
  171.      * @var resource
  172.      * @access private
  173.      */
  174.     var $_logfilefp = 0;
  175.     
  176.     /**
  177.      * @var string
  178.      * @access private
  179.      */
  180.     var $_logfile = 'Net_SmartIRC.log';
  181.     
  182.     /**
  183.      * @var integer
  184.      * @access private
  185.      */
  186.     var $_disconnecttime = 1000;
  187.     
  188.     /**
  189.      * @var boolean
  190.      * @access private
  191.      */
  192.     var $_loggedin = false;
  193.     
  194.     /**
  195.      * @var boolean
  196.      * @access private
  197.      */
  198.     var $_benchmark = false;
  199.     
  200.     /**
  201.      * @var integer
  202.      * @access private
  203.      */
  204.     var $_benchmark_starttime;
  205.     
  206.     /**
  207.      * @var integer
  208.      * @access private
  209.      */
  210.     var $_benchmark_stoptime;
  211.     
  212.     /**
  213.      * @var integer
  214.      * @access private
  215.      */
  216.     var $_actionhandlerid = 0;
  217.     
  218.     /**
  219.      * @var integer
  220.      * @access private
  221.      */
  222.     var $_timehandlerid = 0;
  223.     
  224.     /**
  225.      * @var array
  226.      * @access private
  227.      */
  228.     var $_motd = array();
  229.     
  230.     /**
  231.      * @var array
  232.      * @access private
  233.      */
  234.     var $_channels = array();
  235.     
  236.     /**
  237.      * @var boolean
  238.      * @access private
  239.      */
  240.     var $_channelsyncing = false;
  241.     
  242.     /**
  243.      * @var string
  244.      * @access private
  245.      */
  246.     var $_ctcpversion;
  247.     
  248.     /**
  249.      * @var mixed
  250.      * @access private
  251.      */
  252.     var $_mintimer = false;
  253.     
  254.     /**
  255.      * @var integer
  256.      * @access private
  257.      */
  258.     var $_maxtimer = 300000;
  259.     
  260.     /**
  261.      * @var integer
  262.      * @access private
  263.      */
  264.     var $_txtimeout = 300;
  265.     
  266.     /**
  267.      * @var integer
  268.      * @access private
  269.      */
  270.     var $_rxtimeout = 300;
  271.     
  272.     /**
  273.      * @var integer
  274.      * @access private
  275.      */
  276.     var $_selecttimeout;
  277.     
  278.     /**
  279.      * @var integer
  280.      * @access private
  281.      */
  282.     var $_lastrx;
  283.     
  284.     /**
  285.      * @var integer
  286.      * @access private
  287.      */
  288.     var $_lasttx;
  289.     
  290.     /**
  291.      * @var boolean
  292.      * @access private
  293.      */
  294.     var $_autoreconnect = false;
  295.     
  296.     /**
  297.      * @var boolean
  298.      * @access private
  299.      */
  300.     var $_autoretry = false;
  301.     
  302.     /**
  303.      * All IRC replycodes, the index is the replycode name.
  304.      *
  305.      * @see $SMARTIRC_replycodes
  306.      * @var array
  307.      * @access public
  308.      */
  309.     var $replycodes;
  310.     
  311.     /**
  312.      * All numeric IRC replycodes, the index is the numeric replycode.
  313.      *
  314.      * @see $SMARTIRC_nreplycodes
  315.      * @var array
  316.      * @access public
  317.      */
  318.     var $nreplycodes;
  319.     
  320.     /**
  321.      * Stores all channels in this array where we are joined, works only if channelsyncing is activated.
  322.      * Eg. for accessing a user, use it like this: (in this example the SmartIRC object is stored in $irc)
  323.      * $irc->channel['#test']->users['meebey']->nick;
  324.      *
  325.      * @see setChannelSyncing()
  326.      * @see Net_SmartIRC_channel
  327.      * @see Net_SmartIRC_channeluser
  328.      * @var array
  329.      * @access public
  330.      */
  331.     var $channel;
  332.     
  333.     /**
  334.      * Constructor. Initiales the messagebuffer and "links" the replycodes from
  335.      * global into properties. Also some PHP runtime settings are configured.
  336.      *
  337.      * @access public
  338.      * @return void
  339.      */
  340.     function Net_SmartIRC_base()
  341.     {
  342.         // precheck
  343.         $this->_checkPHPVersion();
  344.         
  345.         ob_implicit_flush(true);
  346.         @set_time_limit(0);
  347.         ignore_user_abort(true);
  348.         $this->_messagebuffer[SMARTIRC_CRITICAL] = array();
  349.         $this->_messagebuffer[SMARTIRC_HIGH] = array();
  350.         $this->_messagebuffer[SMARTIRC_MEDIUM] = array();
  351.         $this->_messagebuffer[SMARTIRC_LOW] = array();
  352.         $this->replycodes = &$GLOBALS['SMARTIRC_replycodes'];
  353.         $this->nreplycodes = &$GLOBALS['SMARTIRC_nreplycodes'];
  354.         
  355.         // hack till PHP allows (PHP5) $object->method($param)->$object
  356.         $this->channel = &$this->_channels;
  357.         // another hack
  358.         $this->user = &$this->_users;
  359.         
  360.         if (isset($_SERVER['REQUEST_METHOD'])) {
  361.             // the script is called from a browser, lets set default log destination
  362.             // to SMARTIRC_BROWSEROUT (makes browser friendly output)
  363.             $this->setLogdestination(SMARTIRC_BROWSEROUT);
  364.         }
  365.     }
  366.     
  367.     /**
  368.      * Enables/disables the usage of real sockets.
  369.      *
  370.      * Enables/disables the usage of real sockets instead of fsocks
  371.      * (works only if your PHP build has loaded the PHP socket extension)
  372.      * Default: false
  373.      *
  374.      * @param bool $boolean
  375.      * @return void
  376.      * @access public
  377.      */
  378.     function setUseSockets($boolean)
  379.     {
  380.         if ($boolean === true) {
  381.             if (@extension_loaded('sockets')) {
  382.                 $this->_usesockets = true;
  383.             } else {
  384.                 $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: socket extension not loaded, trying to load it...', __FILE__, __LINE__);
  385.                 
  386.                 if (strtoupper(substr(PHP_OS, 0,3) == 'WIN')) {
  387.                     $load_status = @dl('php_sockets.dll');
  388.                 } else {
  389.                     $load_status = @dl('sockets.so');
  390.                 }
  391.  
  392.                 if ($load_status) {
  393.                     $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: socket extension succesfully loaded', __FILE__, __LINE__);
  394.                     $this->_usesockets = true;
  395.                 } else {
  396.                     $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: couldn\'t load the socket extension', __FILE__, __LINE__);
  397.                     $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: your PHP build doesn\'t support real sockets, will use fsocks instead', __FILE__, __LINE__);
  398.                     $this->_usesockets = false;
  399.                 }
  400.             }
  401.         } else {
  402.             $this->_usesockets = false;
  403.         }
  404.     }
  405.     
  406.     /**
  407.      * Sets the level of debug messages.
  408.      *
  409.      * Sets the debug level (bitwise), useful for testing/developing your code.
  410.      * Here the list of all possible debug levels:
  411.      * SMARTIRC_DEBUG_NONE
  412.      * SMARTIRC_DEBUG_NOTICE
  413.      * SMARTIRC_DEBUG_CONNECTION
  414.      * SMARTIRC_DEBUG_SOCKET
  415.      * SMARTIRC_DEBUG_IRCMESSAGES
  416.      * SMARTIRC_DEBUG_MESSAGETYPES
  417.      * SMARTIRC_DEBUG_ACTIONHANDLER
  418.      * SMARTIRC_DEBUG_TIMEHANDLER
  419.      * SMARTIRC_DEBUG_MESSAGEHANDLER
  420.      * SMARTIRC_DEBUG_CHANNELSYNCING
  421.      * SMARTIRC_DEBUG_MODULES
  422.      * SMARTIRC_DEBUG_USERSYNCING
  423.      * SMARTIRC_DEBUG_ALL
  424.      *
  425.      * Default: SMARTIRC_DEBUG_NOTICE
  426.      *
  427.      * @see DOCUMENTATION
  428.      * @see SMARTIRC_DEBUG_NOTICE
  429.      * @param integer $level
  430.      * @return void
  431.      * @access public
  432.      */
  433.     function setDebug($level)
  434.     {
  435.         $this->_debug = $level;
  436.     }
  437.     
  438.     /**
  439.      * Enables/disables the benchmark engine.
  440.      * 
  441.      * @param boolean $boolean
  442.      * @return void
  443.      * @access public
  444.      */
  445.     function setBenchmark($boolean)
  446.     {
  447.         if (is_bool($boolean)) {
  448.             $this->_benchmark = $boolean;
  449.         } else {
  450.             $this->_benchmark = false;
  451.         }
  452.     }
  453.     
  454.     /**
  455.      * Deprecated, use setChannelSyncing() instead!
  456.      *
  457.      * @deprecated
  458.      * @param boolean $boolean
  459.      * @return void
  460.      * @access public
  461.      */
  462.     function setChannelSynching($boolean)
  463.     {
  464.         $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: you are using setChannelSynching() which is a deprecated method, use setChannelSyncing() instead!', __FILE__, __LINE__);
  465.         $this->setChannelSyncing($boolean);
  466.     }
  467.     
  468.     /**
  469.      * Enables/disables channel syncing.
  470.      *
  471.      * Channel syncing means, all users on all channel we are joined are tracked in the
  472.      * channel array. This makes it very handy for botcoding.
  473.      * 
  474.      * @param boolean $boolean
  475.      * @return void
  476.      * @access public
  477.      */
  478.     function setChannelSyncing($boolean)
  479.     {
  480.         if (is_bool($boolean)) {
  481.             $this->_channelsyncing = $boolean;
  482.         } else {
  483.             $this->_channelsyncing = false;
  484.         }
  485.         
  486.         if ($this->_channelsyncing == true) {
  487.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: Channel syncing enabled', __FILE__, __LINE__);
  488.         } else {
  489.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: Channel syncing disabled', __FILE__, __LINE__);
  490.         }
  491.     }
  492.     
  493.     /**
  494.      * Sets the CTCP version reply string.
  495.      * 
  496.      * @param string $versionstring
  497.      * @return void
  498.      * @access public
  499.      */
  500.     function setCtcpVersion($versionstring)
  501.     {
  502.         $this->_ctcpversion = $versionstring;
  503.     }
  504.     
  505.     /**
  506.      * Sets the destination of all log messages.
  507.      *
  508.      * Sets the destination of log messages.
  509.      * $type can be:
  510.      * SMARTIRC_FILE for saving the log into a file
  511.      * SMARTIRC_STDOUT for echoing the log to stdout
  512.      * SMARTIRC_SYSLOG for sending the log to the syslog
  513.      * Default: SMARTIRC_STDOUT
  514.      *
  515.      * @see SMARTIRC_STDOUT
  516.      * @param integer $type must be on of the constants
  517.      * @return void
  518.      * @access public
  519.      */
  520.     function setLogdestination($type)
  521.     {
  522.         switch ($type) {
  523.             case (SMARTIRC_FILE ||
  524.                   SMARTIRC_STDOUT ||
  525.                   SMARTIRC_SYSLOG ||
  526.                   SMARTIRC_BROWSEROUT ||
  527.                   SMARTIRC_NONE):
  528.                 $this->_logdestination = $type;
  529.             break;
  530.             default:
  531.                 $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: unknown logdestination type ('.$type.'), will use STDOUT instead', __FILE__, __LINE__);
  532.                 $this->_logdestination = SMARTIRC_STDOUT;
  533.         }
  534.     }
  535.     
  536.     /**
  537.      * Sets the file for the log if the destination is set to file.
  538.      *
  539.      * Sets the logfile, if {@link setLogdestination logdestination} is set to SMARTIRC_FILE.
  540.      * This should be only used with full path!
  541.      *
  542.      * @param string $file 
  543.      * @return void
  544.      * @access public
  545.      */
  546.     function setLogfile($file)
  547.     {
  548.         $this->_logfile = $file;
  549.     }
  550.     
  551.     /**
  552.      * Sets the delaytime before closing the socket when disconnect.
  553.      *
  554.      * @param integer $milliseconds
  555.      * @return void
  556.      * @access public
  557.      */
  558.     function setDisconnecttime($milliseconds)
  559.     {
  560.         if (is_integer($milliseconds) && $milliseconds >= 100) {
  561.             $this->_disconnecttime = $milliseconds;
  562.         } else {
  563.             $this->_disconnecttime = 100;
  564.         }
  565.     }
  566.     
  567.     /**
  568.      * Sets the delay for receiving data from the IRC server.
  569.      *
  570.      * Sets the delaytime between messages that are received, this reduces your CPU load.
  571.      * Don't set this too low (min 100ms).
  572.      * Default: 100
  573.      *
  574.      * @param integer $milliseconds
  575.      * @return void
  576.      * @access public
  577.      */
  578.     function setReceivedelay($milliseconds)
  579.     {
  580.         if (is_integer($milliseconds) && $milliseconds >= 100) {
  581.             $this->_receivedelay = $milliseconds;
  582.         } else {
  583.             $this->_receivedelay = 100;
  584.         }
  585.     }
  586.     
  587.     /**
  588.      * Sets the delay for sending data to the IRC server.
  589.      *
  590.      * Sets the delaytime between messages that are sent, because IRC servers doesn't like floods.
  591.      * This will avoid sending your messages too fast to the IRC server.
  592.      * Default: 250
  593.      *
  594.      * @param integer $milliseconds
  595.      * @return void
  596.      * @access public
  597.      */
  598.     function setSenddelay($milliseconds)
  599.     {
  600.         if (is_integer($milliseconds)) {
  601.             $this->_senddelay = $milliseconds;
  602.         } else {
  603.             $this->_senddelay = 250;
  604.         }
  605.     }
  606.     
  607.     /**
  608.      * Enables/disables autoreconnecting.
  609.      * 
  610.      * @param boolean $boolean
  611.      * @return void
  612.      * @access public
  613.      */
  614.     function setAutoReconnect($boolean)
  615.     {
  616.         if (is_bool($boolean)) {
  617.             $this->_autoreconnect = $boolean;
  618.         } else {
  619.             $this->_autoreconnect = false;
  620.         }
  621.     }
  622.     
  623.     /**
  624.      * Enables/disables autoretry for connecting to a server.
  625.      * 
  626.      * @param boolean $boolean
  627.      * @return void
  628.      * @access public
  629.      */
  630.     function setAutoRetry($boolean)
  631.     {
  632.         if (is_bool($boolean)) {
  633.             $this->_autoretry = $boolean;
  634.         } else {
  635.             $this->_autoretry = false;
  636.         }
  637.     }
  638.     
  639.     /**
  640.      * Sets the receive timeout.
  641.      *
  642.      * If the timeout occurs, the connection will be reinitialized
  643.      * Default: 300 seconds
  644.      *
  645.      * @param integer $seconds
  646.      * @return void
  647.      * @access public
  648.      */
  649.     function setReceiveTimeout($seconds)
  650.     {
  651.         if (is_integer($seconds)) {
  652.             $this->_rxtimeout = $seconds;
  653.         } else {
  654.             $this->_rxtimeout = 300;
  655.         }
  656.     }
  657.     
  658.     /**
  659.      * Sets the transmit timeout.
  660.      *
  661.      * If the timeout occurs, the connection will be reinitialized
  662.      * Default: 300 seconds
  663.      *
  664.      * @param integer $seconds
  665.      * @return void
  666.      * @access public
  667.      */
  668.     function setTransmitTimeout($seconds)
  669.     {
  670.         if (is_integer($seconds)) {
  671.             $this->_txtimeout = $seconds;
  672.         } else {
  673.             $this->_txtimeout = 300;
  674.         }
  675.     }
  676.     
  677.     /**
  678.      * Starts the benchmark (sets the counters).
  679.      *
  680.      * @return void
  681.      * @access public
  682.      */
  683.     function startBenchmark()
  684.     {
  685.         $this->_benchmark_starttime = $this->_microint();
  686.         $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark started', __FILE__, __LINE__);
  687.     }
  688.     
  689.     /**
  690.      * Stops the benchmark and displays the result.
  691.      *
  692.      * @return void
  693.      * @access public
  694.      */
  695.     function stopBenchmark()
  696.     {
  697.         $this->_benchmark_stoptime = $this->_microint();
  698.         $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark stopped', __FILE__, __LINE__);
  699.         
  700.         if ($this->_benchmark) {
  701.             $this->showBenchmark();
  702.         }
  703.     }
  704.     
  705.     /**
  706.      * Shows the benchmark result.
  707.      *
  708.      * @return void
  709.      * @access public
  710.      */
  711.     function showBenchmark()
  712.     {
  713.         $this->log(SMARTIRC_DEBUG_NOTICE, 'benchmark time: '.((float)$this->_benchmark_stoptime-(float)$this->_benchmark_starttime), __FILE__, __LINE__);
  714.     }
  715.     
  716.     /**
  717.      * Adds an entry to the log.
  718.      *
  719.      * Adds an entry to the log with Linux style log format.
  720.      * Possible $level constants (can also be combined with "|"s)
  721.      * SMARTIRC_DEBUG_NONE
  722.      * SMARTIRC_DEBUG_NOTICE
  723.      * SMARTIRC_DEBUG_CONNECTION
  724.      * SMARTIRC_DEBUG_SOCKET
  725.      * SMARTIRC_DEBUG_IRCMESSAGES
  726.      * SMARTIRC_DEBUG_MESSAGETYPES
  727.      * SMARTIRC_DEBUG_ACTIONHANDLER
  728.      * SMARTIRC_DEBUG_TIMEHANDLER
  729.      * SMARTIRC_DEBUG_MESSAGEHANDLER
  730.      * SMARTIRC_DEBUG_CHANNELSYNCING
  731.      * SMARTIRC_DEBUG_MODULES
  732.      * SMARTIRC_DEBUG_USERSYNCING
  733.      * SMARTIRC_DEBUG_ALL
  734.      *
  735.      * @see SMARTIRC_DEBUG_NOTICE
  736.      * @param integer $level bit constants (SMARTIRC_DEBUG_*)
  737.      * @param string $entry the new log entry
  738.      * @return void
  739.      * @access public
  740.      */
  741.     function log($level, $entry, $file = null, $line = null)
  742.     {
  743.         // prechecks
  744.         if (!(is_integer($level)) ||
  745.             !($level & SMARTIRC_DEBUG_ALL)) {
  746.             $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: invalid log level passed to log() ('.$level.')', __FILE__, __LINE__);
  747.             return;
  748.         }
  749.         
  750.         if (!($level & $this->_debug) ||
  751.              ($this->_logdestination == SMARTIRC_NONE)) {
  752.             return;
  753.         }
  754.         
  755.         if (substr($entry, -1) != "\n") {
  756.             $entry .= "\n";
  757.         }
  758.         
  759.         if ($file !== null &&
  760.             $line !== null) {
  761.             $file = basename($file);
  762.             $entry = $file.'('.$line.') '.$entry;
  763.         } else {
  764.             $entry = 'unknown(0) '.$entry;
  765.         }
  766.         
  767.         $formatedentry = date('M d H:i:s ').$entry;
  768.         switch ($this->_logdestination) {
  769.             case SMARTIRC_STDOUT:
  770.                 echo $formatedentry;
  771.                 flush();
  772.             break;
  773.             case SMARTIRC_BROWSEROUT:
  774.                 echo '<pre>'.htmlentities($formatedentry).'</pre>';
  775.             break;
  776.             case SMARTIRC_FILE:
  777.                 if (!is_resource($this->_logfilefp)) {
  778.                     if ($this->_logfilefp === null) {
  779.                         // we reconncted and don't want to destroy the old log entries
  780.                         $this->_logfilefp = @fopen($this->_logfile,'a');
  781.                     } else {
  782.                         $this->_logfilefp = @fopen($this->_logfile,'w');
  783.                     }
  784.                 }
  785.                 @fwrite($this->_logfilefp, $formatedentry);
  786.                 fflush($this->_logfilefp);
  787.             break;
  788.             case SMARTIRC_SYSLOG:
  789.                 define_syslog_variables();
  790.                 if (!is_int($this->_logfilefp)) {
  791.                     $this->_logfilefp = openlog('Net_SmartIRC', LOG_NDELAY, LOG_DAEMON);
  792.                 }
  793.                 syslog(LOG_INFO, $entry);
  794.             break;
  795.         }
  796.     }
  797.     
  798.     /**
  799.      * Returns the full motd.
  800.      *
  801.      * @return array
  802.      * @access public
  803.      */
  804.     function getMotd()
  805.     {
  806.         return $this->_motd;
  807.     }
  808.     
  809.     /**
  810.      * Returns the usermode.
  811.      *
  812.      * @return string
  813.      * @access public
  814.      */
  815.     function getUsermode()
  816.     {
  817.         return $this->_usermode;
  818.     }
  819.     
  820.     /**
  821.      * Creates the sockets and connects to the IRC server on the given port.
  822.      *
  823.      * @param string $address 
  824.      * @param integer $port
  825.      * @return void
  826.      * @access public
  827.      */
  828.     function connect($address, $port)
  829.     {
  830.         $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connecting', __FILE__, __LINE__);
  831.         $this->_address = $address;
  832.         $this->_port = $port;
  833.         
  834.         if ($this->_usesockets == true) {
  835.             $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: using real sockets', __FILE__, __LINE__);
  836.             $this->_socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  837.             $result = @socket_connect($this->_socket, $this->_address, $this->_port);
  838.         } else {
  839.             $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: using fsockets', __FILE__, __LINE__);
  840.             $result = @fsockopen($this->_address, $this->_port, $errno, $errstr);
  841.         }
  842.         
  843.         if ($result === false) {
  844.             if ($this->_usesockets == true) {
  845.                 $error = socket_strerror(socket_last_error($this->_socket));
  846.             } else {
  847.                 $error = $errstr.' ('.$errno.')';
  848.             }
  849.             
  850.             $error_msg = 'couldn\'t connect to "'.$address.'" reason: "'.$error.'"';
  851.             $this->log(SMARTIRC_DEBUG_NOTICE, 'DEBUG_NOTICE: '.$error_msg, __FILE__, __LINE__);
  852.             // TODO! muss return wert sein
  853.             $this->throwError($error_msg);
  854.             
  855.             // doesn't work somehow.... I only want to retry 4 times! no endless loop (causes segfault)
  856.             static $tries = 0;
  857.             if ($this->_autoretry == true && $tries < 5) {
  858.                 $this->reconnect();
  859.                 $tries++;
  860.             } else {
  861.                 die();
  862.             }
  863.         } else {
  864.             $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: connected', __FILE__, __LINE__);
  865.             
  866.             if ($this->_usesockets != true) {
  867.                 $this->_socket = $result;
  868.                 $this->log(SMARTIRC_DEBUG_SOCKET, 'DEBUG_SOCKET: activating nonblocking fsocket mode', __FILE__, __LINE__);
  869.                 socket_set_blocking($this->_socket, false);
  870.             }
  871.         }
  872.         
  873.         $this->_lastrx = time();
  874.         $this->_lasttx = $this->_lastrx;
  875.         $this->_updatestate();
  876.         
  877.         if ($result !== false) {
  878.             return true;
  879.         } else {
  880.             return false;
  881.         }
  882.     }
  883.     
  884.     /**
  885.      * Disconnects from the IRC server nicely with a QUIT or just destroys the socket.
  886.      *
  887.      * Disconnects from the IRC server in the given quickness mode.
  888.      * $quickdisconnect:
  889.      * true, just close the socket
  890.      * false, send QUIT and wait {@link $_disconnectime $_disconnectime} before closing the socket
  891.      *
  892.      * @param boolean $quickdisconnect default: false
  893.      * @return boolean
  894.      * @access public
  895.      */
  896.     function disconnect($quickdisconnect = false)
  897.     {
  898.         if ($this->_state() == SMARTIRC_STATE_CONNECTED) {
  899.             if ($quickdisconnect == false) {
  900.                 $this->_send('QUIT', SMARTIRC_CRITICAL);
  901.                 usleep($this->_disconnecttime*1000);
  902.             }
  903.             
  904.             if ($this->_usesockets == true) {
  905.                 @socket_shutdown($this->_socket);
  906.                 @socket_close($this->_socket);
  907.             } else {
  908.                 fclose($this->_socket);
  909.             }
  910.             
  911.             $this->_updatestate();
  912.             $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: disconnected', __FILE__, __LINE__);
  913.         } else {
  914.             return false;
  915.         }
  916.         
  917.         if ($this->_channelsyncing == true) {
  918.             // let's clean our channel array
  919.             $this->_channels = array();
  920.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: cleaned channel array', __FILE__, __LINE__);
  921.         }
  922.         
  923.         if ($this->_logdestination == SMARTIRC_FILE) {
  924.             fclose($this->_logfilefp);
  925.             $this->_logfilefp = null;
  926.         } else if ($this->_logdestination == SMARTIRC_SYSLOG) {
  927.             closelog();
  928.         }
  929.         
  930.         return true;
  931.     }
  932.     
  933.     /**
  934.      * Reconnects to the IRC server with the same login info,
  935.      * it also rejoins the channels
  936.      *
  937.      * @return void
  938.      * @access public
  939.      */
  940.     function reconnect()
  941.     {
  942.         $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: reconnecting...', __FILE__, __LINE__);
  943.         
  944.         // remember in which channels we are joined
  945.         $channels = array();
  946.         foreach ($this->_channels as $value) {
  947.             if (empty($value->key)) {
  948.                 $channels[] = array('name' => $value->name);
  949.             } else {
  950.                 $channels[] = array('name' => $value->name, 'key' => $value->key);
  951.             }
  952.         }
  953.         
  954.         $this->disconnect(true);
  955.         $this->connect($this->_address, $this->_port);
  956.         $this->login($this->_nick, $this->_realname, $this->_usermode, $this->_username, $this->_password);
  957.         
  958.         // rejoin the channels
  959.         foreach ($channels as $value) {
  960.             if (isset($value['key'])) {
  961.                 $this->join($value['name'], $value['key']);
  962.             } else {
  963.                 $this->join($value['name']);
  964.             }
  965.         }
  966.     }
  967.     
  968.     /**
  969.      * login and register nickname on the IRC network
  970.      *
  971.      * Registers the nickname and user information on the IRC network.
  972.      *
  973.      * @param string $nick
  974.      * @param string $realname
  975.      * @param integer $usermode
  976.      * @param string $username
  977.      * @param string $password
  978.      * @return void
  979.      * @access public
  980.      */
  981.     function login($nick, $realname, $usermode = 0, $username = null, $password = null)
  982.     {
  983.         $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: logging in', __FILE__, __LINE__);
  984.         
  985.         $this->_nick = str_replace(' ', '', $nick);
  986.         $this->_realname = $realname;
  987.         
  988.         if ($username !== null) {
  989.             $this->_username = str_replace(' ', '', $username);
  990.         } else {
  991.             $this->_username = str_replace(' ', '', exec('whoami'));
  992.         }
  993.         
  994.         if ($password !== null) {
  995.             $this->_password = $password;
  996.             $this->_send('PASS '.$this->_password, SMARTIRC_CRITICAL);
  997.         }
  998.         
  999.         if (!is_numeric($usermode)) {
  1000.             $this->log(SMARTIRC_DEBUG_NOTICE, 'DEBUG_NOTICE: login() usermode ('.$usermode.') is not valid, will use 0 instead', __FILE__, __LINE__);
  1001.             $usermode = 0;
  1002.         }
  1003.         
  1004.         $this->_send('NICK '.$this->_nick, SMARTIRC_CRITICAL);
  1005.         $this->_send('USER '.$this->_username.' '.$usermode.' '.SMARTIRC_UNUSED.' :'.$this->_realname, SMARTIRC_CRITICAL);
  1006.     }
  1007.     
  1008.     // </IRC methods>
  1009.     
  1010.     /**
  1011.      * checks if we or the given user is joined to the specified channel and returns the result
  1012.      * ChannelSyncing is required for this.
  1013.      *
  1014.      * @see setChannelSyncing
  1015.      * @param string $channel
  1016.      * @param string $nickname
  1017.      * @return boolean
  1018.      * @access public
  1019.      */
  1020.     function isJoined($channel, $nickname = null)
  1021.     {
  1022.         if ($this->_channelsyncing != true) {
  1023.             $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isJoined() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__);
  1024.             return false;
  1025.         }
  1026.         
  1027.         if ($nickname === null) {
  1028.             $nickname = $this->_nick;
  1029.         }
  1030.         
  1031.         if (isset($this->_channels[strtolower($channel)]->users[strtolower($nickname)])) {
  1032.             return true;
  1033.         }
  1034.         
  1035.         return false;
  1036.     }
  1037.     
  1038.     /**
  1039.      * Checks if we or the given user is opped on the specified channel and returns the result.
  1040.      * ChannelSyncing is required for this.
  1041.      *
  1042.      * @see setChannelSyncing
  1043.      * @param string $channel
  1044.      * @param string $nickname
  1045.      * @return boolean
  1046.      * @access public
  1047.      */
  1048.     function isOpped($channel, $nickname = null)
  1049.     {
  1050.         if ($this->_channelsyncing != true) {
  1051.             $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isOpped() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__);
  1052.             return false;
  1053.         }
  1054.         
  1055.         if ($nickname === null) {
  1056.             $nickname = $this->_nick;
  1057.         }
  1058.         
  1059.         if ($this->isJoined($channel, $nickname)) {
  1060.             if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->op) {
  1061.                 return true;
  1062.             }
  1063.         }
  1064.         
  1065.         return false;
  1066.     }
  1067.     
  1068.     /**
  1069.      * Checks if we or the given user is voiced on the specified channel and returns the result.
  1070.      * ChannelSyncing is required for this.
  1071.      *
  1072.      * @see setChannelSyncing
  1073.      * @param string $channel
  1074.      * @param string $nickname
  1075.      * @return boolean
  1076.      * @access public
  1077.      */
  1078.     function isVoiced($channel, $nickname = null)
  1079.     {
  1080.         if ($this->_channelsyncing != true) {
  1081.             $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isVoiced() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__);
  1082.             return false;
  1083.         }
  1084.         
  1085.         if ($nickname === null) {
  1086.             $nickname = $this->_nick;
  1087.         }
  1088.         
  1089.         if ($this->isJoined($channel, $nickname)) {
  1090.             if ($this->_channels[strtolower($channel)]->users[strtolower($nickname)]->voice) {
  1091.                 return true;
  1092.             }
  1093.         }
  1094.         
  1095.         return false;
  1096.     }
  1097.     
  1098.     /**
  1099.      * Checks if the hostmask is on the specified channel banned and returns the result.
  1100.      * ChannelSyncing is required for this.
  1101.      *
  1102.      * @see setChannelSyncing
  1103.      * @param string $channel
  1104.      * @param string $hostmask
  1105.      * @return boolean
  1106.      * @access public
  1107.      */
  1108.     function isBanned($channel, $hostmask)
  1109.     {
  1110.         if ($this->_channelsyncing != true) {
  1111.             $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: isBanned() is called and the required Channel Syncing is not activated!', __FILE__, __LINE__);
  1112.             return false;
  1113.         }
  1114.         
  1115.         if ($this->isJoined($channel)) {
  1116.             $result = array_search($hostmask, $this->_channels[strtolower($channel)]->bans);
  1117.             
  1118.             if ($result !== false) {
  1119.                 return true;
  1120.             }
  1121.         }
  1122.         
  1123.         return false;
  1124.     }
  1125.  
  1126.     /**
  1127.      * goes into receive mode
  1128.      *
  1129.      * Goes into receive and idle mode. Only call this if you want to "spawn" the bot.
  1130.      * No further lines of PHP code will be processed after this call, only the bot methods!
  1131.      *
  1132.      * @return boolean
  1133.      * @access public
  1134.      */
  1135.     function listen()
  1136.     {
  1137.         if ($this->_state() == SMARTIRC_STATE_CONNECTED) {
  1138.             $this->_rawreceive();
  1139.             return true;
  1140.         } else {
  1141.             return false;
  1142.         }
  1143.     }
  1144.     
  1145.     /**
  1146.      * waits for a special message type and puts the answer in $result
  1147.      *
  1148.      * Creates a special actionhandler for that given TYPE and returns the answer.
  1149.      * This will only receive the requested type, immediately quit and disconnect from the IRC server.
  1150.      * Made for showing IRC statistics on your homepage, or other IRC related information.
  1151.      *
  1152.      * @param integer $messagetype see in the documentation 'Message Types'
  1153.      * @return array answer from the IRC server for this $messagetype
  1154.      * @access public
  1155.      */
  1156.     function listenFor($messagetype)
  1157.     {
  1158.         $listenfor = &new Net_SmartIRC_listenfor();
  1159.         $this->registerActionhandler($messagetype, '.*', $listenfor, 'handler');
  1160.         $this->listen();
  1161.         $result = $listenfor->result;
  1162.         
  1163.         if (isset($listenfor)) {
  1164.             unset($listenfor);
  1165.         }
  1166.         
  1167.         return $result;
  1168.     }
  1169.     
  1170.     /**
  1171.      * waits for a special message type and puts the answer in $result
  1172.      *
  1173.      * Creates a special actionhandler for that given TYPE and returns the answer.
  1174.      * This will only receive the requested type, immediately quit and disconnect from the IRC server.
  1175.      * Made for showing IRC statistics on your homepage, or other IRC related information.
  1176.      * This special version of listenFor() stores the whole ircdata object, not just the message!
  1177.      *
  1178.      * @param integer $messagetype see in the documentation 'Message Types'
  1179.      * @return array answer from the IRC server for this $messagetype
  1180.      * @access public
  1181.      */
  1182.     function objListenFor($messagetype)
  1183.     {
  1184.         $objlistenfor = &new Net_SmartIRC_objListenFor();
  1185.         $this->registerActionhandler($messagetype, '.*', $objlistenfor, 'handler');
  1186.         $this->listen();
  1187.         $result = $objlistenfor->result;
  1188.         
  1189.         if (isset($objlistenfor)) {
  1190.             unset($objlistenfor);
  1191.         }
  1192.         
  1193.         return $result;
  1194.     }    
  1195.     
  1196.     /**
  1197.      * registers a new actionhandler and returns the assigned id
  1198.      *
  1199.      * Registers an actionhandler in Net_SmartIRC for calling it later.
  1200.      * The actionhandler id is needed for unregistering the actionhandler.
  1201.      *
  1202.      * @see example.php
  1203.      * @param integer $handlertype bits constants, see in this documentation Message Types
  1204.      * @param string $regexhandler the message that has to be in the IRC message in regex syntax
  1205.      * @param object $object a reference to the objects of the method
  1206.      * @param string $methodname the methodname that will be called when the handler happens
  1207.      * @return integer assigned actionhandler id
  1208.      * @access public
  1209.      */
  1210.     function registerActionhandler($handlertype, $regexhandler, &$object, $methodname)
  1211.     {
  1212.         // precheck
  1213.         if (!$this->_isValidType($handlertype)) {
  1214.             $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: passed invalid handlertype to registerActionhandler()', __FILE__, __LINE__);
  1215.             return false;
  1216.         }
  1217.         
  1218.         $id = $this->_actionhandlerid++;
  1219.         $newactionhandler = &new Net_SmartIRC_actionhandler();
  1220.         
  1221.         $newactionhandler->id = $id;
  1222.         $newactionhandler->type = $handlertype;
  1223.         $newactionhandler->message = $regexhandler;
  1224.         $newactionhandler->object = &$object;
  1225.         $newactionhandler->method = $methodname;
  1226.         
  1227.         $this->_actionhandler[] = &$newactionhandler;
  1228.         $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') registered', __FILE__, __LINE__);
  1229.         return $id;
  1230.     }
  1231.     
  1232.     /**
  1233.      * unregisters an existing actionhandler
  1234.      *
  1235.      * @param integer $handlertype
  1236.      * @param string $regexhandler
  1237.      * @param object $object
  1238.      * @param string $methodname
  1239.      * @return boolean
  1240.      * @access public
  1241.      */
  1242.     function unregisterActionhandler($handlertype, $regexhandler, &$object, $methodname)
  1243.     {
  1244.         // precheck
  1245.         if (!$this->_isValidType($handlertype)) {
  1246.             $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: passed invalid handlertype to unregisterActionhandler()', __FILE__, __LINE__);
  1247.             return false;
  1248.         }
  1249.         
  1250.         $handler = &$this->_actionhandler;
  1251.         $handlercount = count($handler);
  1252.         
  1253.         for ($i = 0; $i < $handlercount; $i++) {
  1254.             $handlerobject = &$handler[$i];
  1255.                         
  1256.             if ($handlerobject->type == $handlertype &&
  1257.                 $handlerobject->message == $regexhandler &&
  1258.                 $handlerobject->method == $methodname) {
  1259.                 
  1260.                 $id = $handlerobject->id;
  1261.                 
  1262.                 if (isset($this->_actionhandler[$i])) {
  1263.                     unset($this->_actionhandler[$i]);
  1264.                 }
  1265.                 
  1266.                 $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered', __FILE__, __LINE__);
  1267.                 $this->_reorderactionhandler();
  1268.                 return true;
  1269.             }
  1270.         }
  1271.         
  1272.         $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: could not find actionhandler type: "'.$handlertype.'" message: "'.$regexhandler.'" method: "'.$methodname.'" from object "'.get_class($object).'" _not_ unregistered', __FILE__, __LINE__);
  1273.         return false;
  1274.     }
  1275.     
  1276.     /**
  1277.      * unregisters an existing actionhandler via the id
  1278.      *
  1279.      * @param integer $id
  1280.      * @return boolean
  1281.      * @access public
  1282.      */
  1283.     function unregisterActionid($id)
  1284.     {
  1285.         $handler = &$this->_actionhandler;
  1286.         $handlercount = count($handler);
  1287.         for ($i = 0; $i < $handlercount; $i++) {
  1288.             $handlerobject = &$handler[$i];
  1289.                         
  1290.             if ($handlerobject->id == $id) {
  1291.                 if (isset($this->_actionhandler[$i])) {
  1292.                     unset($this->_actionhandler[$i]);
  1293.                 }
  1294.                 
  1295.                 $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler('.$id.') unregistered', __FILE__, __LINE__);
  1296.                 $this->_reorderactionhandler();
  1297.                 return true;
  1298.             }
  1299.         }
  1300.         
  1301.         $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: could not find actionhandler id: '.$id.' _not_ unregistered', __FILE__, __LINE__);
  1302.         return false;
  1303.     }
  1304.     
  1305.     /**
  1306.      * registers a timehandler and returns the assigned id
  1307.      *
  1308.      * Registers a timehandler in Net_SmartIRC, which will be called in the specified interval.
  1309.      * The timehandler id is needed for unregistering the timehandler.
  1310.      *
  1311.      * @see example7.php
  1312.      * @param integer $interval interval time in milliseconds
  1313.      * @param object $object a reference to the objects of the method
  1314.      * @param string $methodname the methodname that will be called when the handler happens
  1315.      * @return integer assigned timehandler id
  1316.      * @access public
  1317.      */
  1318.     function registerTimehandler($interval, &$object, $methodname)
  1319.     {
  1320.         $id = $this->_timehandlerid++;
  1321.         $newtimehandler = &new Net_SmartIRC_timehandler();
  1322.         
  1323.         $newtimehandler->id = $id;
  1324.         $newtimehandler->interval = $interval;
  1325.         $newtimehandler->object = &$object;
  1326.         $newtimehandler->method = $methodname;
  1327.         $newtimehandler->lastmicrotimestamp = $this->_microint();
  1328.         
  1329.         $this->_timehandler[] = &$newtimehandler;
  1330.         $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: timehandler('.$id.') registered', __FILE__, __LINE__);
  1331.         
  1332.         if (($interval < $this->_mintimer) || ($this->_mintimer == false)) {
  1333.             $this->_mintimer = $interval;
  1334.         }
  1335.             
  1336.         return $id;
  1337.     }
  1338.     
  1339.     /**
  1340.      * unregisters an existing timehandler via the id
  1341.      *
  1342.      * @see example7.php
  1343.      * @param integer $id
  1344.      * @return boolean
  1345.      * @access public
  1346.      */
  1347.     function unregisterTimeid($id)
  1348.     {
  1349.         $handler = &$this->_timehandler;
  1350.         $handlercount = count($handler);
  1351.         for ($i = 0; $i < $handlercount; $i++) {
  1352.             $handlerobject = &$handler[$i];
  1353.             
  1354.             if ($handlerobject->id == $id) {
  1355.                 if (isset($this->_timehandler[$i])) {
  1356.                     unset($this->_timehandler[$i]);
  1357.                 }
  1358.                 
  1359.                 $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: timehandler('.$id.') unregistered', __FILE__, __LINE__);
  1360.                 $this->_reordertimehandler();
  1361.                 $this->_updatemintimer();
  1362.                 return true;
  1363.             }
  1364.         }
  1365.         
  1366.         $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: could not find timehandler id: '.$id.' _not_ unregistered', __FILE__, __LINE__);
  1367.         return false;
  1368.     }
  1369.     
  1370.     // <private methods>
  1371.     /**
  1372.      * changes a already used nickname to a new nickname plus 3 random digits
  1373.      *
  1374.      * @return void
  1375.      * @access private
  1376.      */
  1377.     function _nicknameinuse()
  1378.     {
  1379.         $newnickname = substr($this->_nick, 0, 5).rand(0, 999);
  1380.         $this->changeNick($newnickname, SMARTIRC_CRITICAL);
  1381.     }
  1382.     
  1383.     /**
  1384.      * sends an IRC message
  1385.      *
  1386.      * Adds a message to the messagequeue, with the optional priority.
  1387.      * $priority:
  1388.      * SMARTIRC_CRITICAL
  1389.      * SMARTIRC_HIGH
  1390.      * SMARTIRC_MEDIUM
  1391.      * SMARTIRC_LOW
  1392.      *
  1393.      * @param string $data
  1394.      * @param integer $priority must be one of the priority constants
  1395.      * @return boolean
  1396.      * @access private
  1397.      */
  1398.     function _send($data, $priority = SMARTIRC_MEDIUM)
  1399.     {
  1400.         switch ($priority) {
  1401.             case SMARTIRC_CRITICAL:
  1402.                 $this->_rawsend($data);
  1403.                 return true;
  1404.             break;
  1405.             case (SMARTIRC_HIGH||
  1406.                   SMARTIRC_MEDIUM||
  1407.                   SMARTIRC_LOW):
  1408.                 $this->_messagebuffer[$priority][] = $data;
  1409.                 return true;
  1410.             break;
  1411.             default:
  1412.                 $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: message ('.$data.') with an invalid priority passed ('.$priority.'), message is ignored!', __FILE__, __LINE__);
  1413.                 return false;
  1414.         }
  1415.     }
  1416.     
  1417.     /**
  1418.      * checks the buffer if there are messages to send
  1419.      *
  1420.      * @return void
  1421.      * @access private
  1422.      */
  1423.     function _checkbuffer()
  1424.     {
  1425.         if (!$this->_loggedin) {
  1426.             return;
  1427.         }
  1428.         
  1429.         static $highsent = 0;
  1430.         static $lastmicrotimestamp = 0;
  1431.         
  1432.         if ($lastmicrotimestamp == 0) {
  1433.             $lastmicrotimestamp = $this->_microint();
  1434.         }
  1435.         
  1436.         $highcount = count($this->_messagebuffer[SMARTIRC_HIGH]);
  1437.         $mediumcount = count($this->_messagebuffer[SMARTIRC_MEDIUM]);
  1438.         $lowcount = count($this->_messagebuffer[SMARTIRC_LOW]);
  1439.         $this->_messagebuffersize = $highcount+$mediumcount+$lowcount;
  1440.         
  1441.         // don't send them too fast
  1442.         if ($this->_microint() >= ($lastmicrotimestamp+($this->_senddelay/1000))) {
  1443.             if ($highcount > 0 && $highsent <= 2) {
  1444.                 $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_HIGH]));
  1445.                 $lastmicrotimestamp = $this->_microint();
  1446.                 $highsent++;
  1447.             } else if ($mediumcount > 0) {
  1448.                 $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_MEDIUM]));
  1449.                 $lastmicrotimestamp = $this->_microint();
  1450.                 $highsent = 0;
  1451.             } else if ($lowcount > 0) {
  1452.                 $this->_rawsend(array_shift($this->_messagebuffer[SMARTIRC_LOW]));
  1453.                 $lastmicrotimestamp = $this->_microint();
  1454.             }
  1455.         }
  1456.     }
  1457.     
  1458.     /**
  1459.      * Checks the running timers and calls the registered timehandler,
  1460.      * when the interval is reached.
  1461.      *
  1462.      * @return void
  1463.      * @access private
  1464.      */
  1465.     function _checktimer()
  1466.     {
  1467.         if (!$this->_loggedin) {
  1468.             return;
  1469.         }
  1470.         
  1471.         // has to be count() because the array may change during the loop!
  1472.         for ($i = 0; $i < count($this->_timehandler); $i++) {
  1473.             $handlerobject = &$this->_timehandler[$i];
  1474.             $microtimestamp = $this->_microint();
  1475.             if ($microtimestamp >= ($handlerobject->lastmicrotimestamp+($handlerobject->interval/1000))) {
  1476.                 $methodobject = &$handlerobject->object;
  1477.                 $method = $handlerobject->method;
  1478.                 $handlerobject->lastmicrotimestamp = $microtimestamp;
  1479.                 
  1480.                 if (@method_exists($methodobject, $method)) {
  1481.                     $this->log(SMARTIRC_DEBUG_TIMEHANDLER, 'DEBUG_TIMEHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__);
  1482.                     $methodobject->$method($this);
  1483.                 }
  1484.             }
  1485.         }
  1486.     }
  1487.     
  1488.     /**
  1489.      * Checks if a receive or transmit timeout occured and reconnects if configured
  1490.      *
  1491.      * @return void
  1492.      * @access private
  1493.      */
  1494.     function _checktimeout()
  1495.     {
  1496.         if ($this->_autoreconnect == true) {
  1497.             $timestamp = time();
  1498.             if ($this->_lastrx < ($timestamp - $this->_rxtimeout)) {
  1499.                 $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: receive timeout detected, doing reconnect...', __FILE__, __LINE__);
  1500.                 $this->reconnect();
  1501.             } else if ($this->_lasttx < ($timestamp - $this->_txtimeout)) {
  1502.                 $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: transmit timeout detected, doing reconnect...', __FILE__, __LINE__);
  1503.                 $this->reconnect();
  1504.             }
  1505.         }
  1506.     }
  1507.     
  1508.     /**
  1509.      * sends a raw message to the IRC server (don't use this!!)
  1510.      *
  1511.      * Use message() or _send() instead.
  1512.      *
  1513.      * @param string $data
  1514.      * @return boolean
  1515.      * @access private
  1516.      */
  1517.     function _rawsend($data)
  1518.     {
  1519.         if ($this->_state() == SMARTIRC_STATE_CONNECTED) {
  1520.             $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: sent: "'.$data.'"', __FILE__, __LINE__);
  1521.             
  1522.             if ($this->_usesockets == true) {
  1523.                 $result = @socket_write($this->_socket, $data.SMARTIRC_CRLF);
  1524.             } else {
  1525.                 $result = @fwrite($this->_socket, $data.SMARTIRC_CRLF);
  1526.             }
  1527.             
  1528.             
  1529.             if ($result === false) {
  1530.                 return false;
  1531.             } else {
  1532.                 $this->_lasttx = time();
  1533.                 return true;
  1534.             }
  1535.         } else {
  1536.             return false;
  1537.         }
  1538.     }
  1539.     
  1540.     /**
  1541.      * goes into main idle loop for waiting messages from the IRC server
  1542.      *
  1543.      * @return void
  1544.      * @access private
  1545.      */
  1546.     function _rawreceive()
  1547.     {
  1548.         $lastpart = '';
  1549.         $rawdataar = array();
  1550.         
  1551.         while ($this->_state() == SMARTIRC_STATE_CONNECTED) {
  1552.             $this->_checkbuffer();
  1553.             
  1554.             $timeout = $this->_selecttimeout();
  1555.             if ($this->_usesockets == true) {
  1556.                 $sread = array($this->_socket);
  1557.                 $result = @socket_select($sread, $w = null, $e = null, 0, $timeout*1000);
  1558.                 
  1559.                 if ($result == 1) {
  1560.                     // the socket got data to read
  1561.                     $rawdata = @socket_read($this->_socket, 10240);
  1562.                 } else if ($result === false) {
  1563.                     // panic! panic! something went wrong!
  1564.                     $this->log(SMARTIRC_DEBUG_NOTICE, 'WARNING: socket_select() returned false, something went wrong! Reason: '.socket_strerror(socket_last_error()), __FILE__, __LINE__);
  1565.                     exit;
  1566.                 } else {
  1567.                     // no data
  1568.                     $rawdata = null;
  1569.                 }
  1570.             } else {
  1571.                 usleep($this->_receivedelay*1000);
  1572.                 $rawdata = @fread($this->_socket, 10240);
  1573.             }
  1574.             
  1575.             $this->_checktimer();
  1576.             $this->_checktimeout();
  1577.             
  1578.             if ($rawdata !== null && !empty($rawdata)) {
  1579.                 $this->_lastrx = time();
  1580.                 $rawdata = str_replace("\r", '', $rawdata);
  1581.                 $rawdata = $lastpart.$rawdata;
  1582.                 
  1583.                 $lastpart = substr($rawdata, strrpos($rawdata ,"\n")+1);
  1584.                 $rawdata = substr($rawdata, 0, strrpos($rawdata ,"\n"));
  1585.                 $rawdataar = explode("\n", $rawdata);
  1586.             }
  1587.             
  1588.             // loop through our received messages
  1589.             while (count($rawdataar) > 0) {
  1590.                 $rawline = array_shift($rawdataar);
  1591.                 $validmessage = false;
  1592.                 
  1593.                 $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: received: "'.$rawline.'"', __FILE__, __LINE__);
  1594.                 
  1595.                 // building our data packet
  1596.                 $ircdata = &new Net_SmartIRC_data();
  1597.                 $ircdata->rawmessage = $rawline;
  1598.                 $lineex = explode(' ', $rawline);
  1599.                 $ircdata->rawmessageex = $lineex;
  1600.                 $messagecode = $lineex[0];
  1601.                 
  1602.                 if (substr($rawline, 0, 1) == ':') {
  1603.                     $validmessage = true;
  1604.                     $line = substr($rawline, 1);
  1605.                     $lineex = explode(' ', $line);
  1606.                     
  1607.                     // conform to RFC 2812
  1608.                     $from = $lineex[0];
  1609.                     $messagecode = $lineex[1];
  1610.                     $exclamationpos = strpos($from, '!');
  1611.                     $atpos = strpos($from, '@');
  1612.                     $colonpos = strpos($line, ' :');
  1613.                     if ($colonpos !== false) {
  1614.                         // we want the exact position of ":" not beginning from the space
  1615.                         $colonpos += 1;
  1616.                     }
  1617.                     $ircdata->nick = substr($from, 0, $exclamationpos);
  1618.                     $ircdata->ident = substr($from, $exclamationpos+1, ($atpos-$exclamationpos)-1);
  1619.                     $ircdata->host = substr($from, $atpos+1);
  1620.                     $ircdata->type = $this->_gettype($rawline);
  1621.                     $ircdata->from = $from;
  1622.                     if ($colonpos !== false) {
  1623.                         $ircdata->message = substr($line, $colonpos+1);
  1624.                         $ircdata->messageex = explode(' ', $ircdata->message);
  1625.                     }
  1626.                     
  1627.                     if ($ircdata->type & (SMARTIRC_TYPE_CHANNEL|
  1628.                                  SMARTIRC_TYPE_ACTION|
  1629.                                  SMARTIRC_TYPE_MODECHANGE|
  1630.                                  SMARTIRC_TYPE_KICK|
  1631.                                  SMARTIRC_TYPE_PART|
  1632.                                  SMARTIRC_TYPE_JOIN)) {
  1633.                         $ircdata->channel = $lineex[2];
  1634.                     } else if ($ircdata->type & (SMARTIRC_TYPE_WHO|
  1635.                                         SMARTIRC_TYPE_BANLIST|
  1636.                                         SMARTIRC_TYPE_TOPIC|
  1637.                                         SMARTIRC_TYPE_CHANNELMODE)) {
  1638.                         $ircdata->channel = $lineex[3];
  1639.                     } else if ($ircdata->type & SMARTIRC_TYPE_NAME) {
  1640.                         $ircdata->channel = $lineex[4];
  1641.                     }
  1642.                     
  1643.                     if ($ircdata->channel !== null) {
  1644.                         if (substr($ircdata->channel, 0, 1) == ':') {
  1645.                             $ircdata->channel = substr($ircdata->channel, 1);
  1646.                         }
  1647.                     }
  1648.                     
  1649.                     $this->log(SMARTIRC_DEBUG_MESSAGEPARSER, 'DEBUG_MESSAGEPARSER: ircdata nick: "'.$ircdata->nick.
  1650.                                                                 '" ident: "'.$ircdata->ident.
  1651.                                                                 '" host: "'.$ircdata->host.
  1652.                                                                 '" type: "'.$ircdata->type.
  1653.                                                                 '" from: "'.$ircdata->from.
  1654.                                                                 '" channel: "'.$ircdata->channel.
  1655.                                                                 '" message: "'.$ircdata->message.
  1656.                                                                 '"', __FILE__, __LINE__);
  1657.                 }
  1658.                 
  1659.                 // lets see if we have a messagehandler for it
  1660.                 $this->_handlemessage($messagecode, $ircdata);
  1661.                     
  1662.                 if ($validmessage == true) {
  1663.                     // now the actionhandlers are comming
  1664.                     $this->_handleactionhandler($ircdata);
  1665.                 }
  1666.                 
  1667.                 if (isset($ircdata)) {
  1668.                     unset($ircdata);
  1669.                 }
  1670.             }
  1671.         }
  1672.     }
  1673.     
  1674.     /**
  1675.      * sends the pong for keeping alive
  1676.      *
  1677.      * Sends the PONG signal as reply of the PING from the IRC server.
  1678.      *
  1679.      * @param string $data
  1680.      * @return void
  1681.      * @access private
  1682.      */
  1683.     function _pong($data)
  1684.     {
  1685.         $this->log(SMARTIRC_DEBUG_CONNECTION, 'DEBUG_CONNECTION: Ping? Pong!', __FILE__, __LINE__);
  1686.         $this->_send('PONG '.$data, SMARTIRC_CRITICAL);
  1687.     }
  1688.     
  1689.     /**
  1690.      * returns the calculated selecttimeout value
  1691.      *
  1692.      * @return integer selecttimeout in microseconds
  1693.      * @access private
  1694.      */
  1695.     function _selecttimeout() {
  1696.         if ($this->_messagebuffersize == 0) {
  1697.             $this->_selecttimeout = null;
  1698.             
  1699.             if ($this->_mintimer != false) {
  1700.                 $this->_calculateselecttimeout($this->_mintimer);
  1701.             }
  1702.             
  1703.             if ($this->_autoreconnect == true) {
  1704.                 $this->_calculateselecttimeout($this->_rxtimeout*1000);
  1705.             }
  1706.             
  1707.             $this->_calculateselecttimeout($this->_maxtimer);
  1708.             return $this->_selecttimeout;
  1709.         } else {
  1710.             return $this->_senddelay;
  1711.         }
  1712.     }
  1713.     
  1714.     /**
  1715.      * calculates the selecttimeout value
  1716.      *
  1717.      * @return void
  1718.      * @access private
  1719.      */
  1720.     function _calculateselecttimeout($microseconds)
  1721.     {
  1722.         if (($this->_selecttimeout > $microseconds) || $this->_selecttimeout === null) {
  1723.             $this->_selecttimeout = $microseconds;
  1724.         }
  1725.     }
  1726.     
  1727.     /**
  1728.      * updates _mintimer to the smallest timer interval
  1729.      *
  1730.      * @return void
  1731.      * @access private
  1732.      */
  1733.     function _updatemintimer()
  1734.     {
  1735.         $timerarray = array();
  1736.         foreach ($this->_timehandler as $values) {
  1737.             $timerarray[] = $values->interval;
  1738.         }
  1739.         
  1740.         $result = array_multisort($timerarray, SORT_NUMERIC, SORT_ASC);
  1741.         if ($result == true && isset($timerarray[0])) {
  1742.             $this->_mintimer = $timerarray[0];
  1743.         } else {
  1744.             $this->_mintimer = false;
  1745.         }
  1746.     }
  1747.     
  1748.     /**
  1749.      * reorders the actionhandler array, needed after removing one
  1750.      *
  1751.      * @return void
  1752.      * @access private
  1753.      */
  1754.     function _reorderactionhandler()
  1755.     {
  1756.         $orderedactionhandler = array();
  1757.         foreach ($this->_actionhandler as $value) {
  1758.             $orderedactionhandler[] = $value;
  1759.         }
  1760.         $this->_actionhandler = &$orderedactionhandler;
  1761.     }
  1762.     
  1763.     /**
  1764.      * reorders the timehandler array, needed after removing one
  1765.      *
  1766.      * @return void
  1767.      * @access private
  1768.      */
  1769.     function _reordertimehandler()
  1770.     {
  1771.         $orderedtimehandler = array();
  1772.         foreach ($this->_timehandler as $value) {
  1773.             $orderedtimehandler[] = $value;
  1774.         }
  1775.         $this->_timehandler = &$orderedtimehandler;
  1776.     }
  1777.     
  1778.     /**
  1779.      * reorders the modules array, needed after removing one
  1780.      *
  1781.      * @return void
  1782.      * @access private
  1783.      */
  1784.     function _reordermodules()
  1785.     {
  1786.         $orderedmodules = array();
  1787.         foreach ($this->_modules as $value) {
  1788.             $orderedmodules[] = $value;
  1789.         }
  1790.         $this->_modules = &$orderedmodules;
  1791.     }
  1792.  
  1793.     /**
  1794.      * determines the messagetype of $line
  1795.      *
  1796.      * Analyses the type of an IRC message and returns the type.
  1797.      *
  1798.      * @param string $line
  1799.      * @return integer SMARTIRC_TYPE_* constant
  1800.      * @access private
  1801.      */
  1802.     function _gettype($line)
  1803.     {
  1804.         if (preg_match('/^:[^ ]+? [0-9]{3} .+$/', $line) == 1) {
  1805.             $lineex = explode(' ', $line);
  1806.             $code = $lineex[1];
  1807.                 
  1808.             switch ($code) {
  1809.                 case SMARTIRC_RPL_WELCOME:
  1810.                 case SMARTIRC_RPL_YOURHOST:
  1811.                 case SMARTIRC_RPL_CREATED:
  1812.                 case SMARTIRC_RPL_MYINFO:
  1813.                 case SMARTIRC_RPL_BOUNCE:
  1814.                     return SMARTIRC_TYPE_LOGIN;
  1815.                 case SMARTIRC_RPL_LUSERCLIENT:
  1816.                 case SMARTIRC_RPL_LUSEROP:
  1817.                 case SMARTIRC_RPL_LUSERUNKNOWN:
  1818.                 case SMARTIRC_RPL_LUSERME:
  1819.                 case SMARTIRC_RPL_LUSERCHANNELS:
  1820.                     return SMARTIRC_TYPE_INFO;
  1821.                 case SMARTIRC_RPL_MOTDSTART:
  1822.                 case SMARTIRC_RPL_MOTD:
  1823.                 case SMARTIRC_RPL_ENDOFMOTD:
  1824.                     return SMARTIRC_TYPE_MOTD;
  1825.                 case SMARTIRC_RPL_NAMREPLY:
  1826.                 case SMARTIRC_RPL_ENDOFNAMES:
  1827.                     return SMARTIRC_TYPE_NAME;
  1828.                 case SMARTIRC_RPL_WHOREPLY:
  1829.                 case SMARTIRC_RPL_ENDOFWHO:
  1830.                     return SMARTIRC_TYPE_WHO;
  1831.                 case SMARTIRC_RPL_LISTSTART:
  1832.                     return SMARTIRC_TYPE_NONRELEVANT;
  1833.                 case SMARTIRC_RPL_LIST:
  1834.                 case SMARTIRC_RPL_LISTEND:
  1835.                     return SMARTIRC_TYPE_LIST;
  1836.                 case SMARTIRC_RPL_BANLIST:
  1837.                 case SMARTIRC_RPL_ENDOFBANLIST:
  1838.                     return SMARTIRC_TYPE_BANLIST;
  1839.                 case SMARTIRC_RPL_TOPIC:
  1840.                     return SMARTIRC_TYPE_TOPIC;
  1841.                 case SMARTIRC_RPL_WHOISUSER:
  1842.                 case SMARTIRC_RPL_WHOISSERVER:
  1843.                 case SMARTIRC_RPL_WHOISOPERATOR:
  1844.                 case SMARTIRC_RPL_WHOISIDLE:
  1845.                 case SMARTIRC_RPL_ENDOFWHOIS:
  1846.                 case SMARTIRC_RPL_WHOISCHANNELS:
  1847.                     return SMARTIRC_TYPE_WHOIS;
  1848.                 case SMARTIRC_RPL_WHOWASUSER:
  1849.                 case SMARTIRC_RPL_ENDOFWHOWAS:
  1850.                     return SMARTIRC_TYPE_WHOWAS;
  1851.                 case SMARTIRC_RPL_UMODEIS:
  1852.                     return SMARTIRC_TYPE_USERMODE;
  1853.                 case SMARTIRC_RPL_CHANNELMODEIS:
  1854.                     return SMARTIRC_TYPE_CHANNELMODE;
  1855.                 case SMARTIRC_ERR_NICKNAMEINUSE:
  1856.                 case SMARTIRC_ERR_NOTREGISTERED:
  1857.                     return SMARTIRC_TYPE_ERROR;
  1858.                 default:
  1859.                     $this->log(SMARTIRC_DEBUG_IRCMESSAGES, 'DEBUG_IRCMESSAGES: replycode UNKNOWN ('.$code.'): "'.$line.'"', __FILE__, __LINE__);
  1860.             }
  1861.         }
  1862.         
  1863.         if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'ACTION .*'.chr(1).'$/', $line) == 1) {
  1864.             return SMARTIRC_TYPE_ACTION;
  1865.         } else if (preg_match('/^:.*? PRIVMSG .* :'.chr(1).'.*'.chr(1).'$/', $line) == 1) {
  1866.             return SMARTIRC_TYPE_CTCP;
  1867.         } else if (preg_match('/^:.*? PRIVMSG (\&|\#|\+|\!).* :.*$/', $line) == 1) {
  1868.             return SMARTIRC_TYPE_CHANNEL;
  1869.         } else if (preg_match('/^:.*? PRIVMSG .*:.*$/', $line) == 1) {
  1870.             return SMARTIRC_TYPE_QUERY;
  1871.         } else if (preg_match('/^:.*? NOTICE .* :.*$/', $line) == 1) {
  1872.             return SMARTIRC_TYPE_NOTICE;
  1873.         } else if (preg_match('/^:.*? INVITE .* .*$/', $line) == 1) {
  1874.             return SMARTIRC_TYPE_INVITE;
  1875.         } else if (preg_match('/^:.*? JOIN .*$/', $line) == 1) {
  1876.             return SMARTIRC_TYPE_JOIN;
  1877.         } else if (preg_match('/^:.*? TOPIC .* :.*$/', $line) == 1) {
  1878.             return SMARTIRC_TYPE_TOPICCHANGE;
  1879.         } else if (preg_match('/^:.*? NICK .*$/', $line) == 1) {
  1880.             return SMARTIRC_TYPE_NICKCHANGE;
  1881.         } else if (preg_match('/^:.*? KICK .* .*$/', $line) == 1) {
  1882.             return SMARTIRC_TYPE_KICK;
  1883.         } else if (preg_match('/^:.*? PART .*$/', $line) == 1) {
  1884.             return SMARTIRC_TYPE_PART;
  1885.         } else if (preg_match('/^:.*? MODE .* .*$/', $line) == 1) {
  1886.             return SMARTIRC_TYPE_MODECHANGE;
  1887.         } else if (preg_match('/^:.*? QUIT :.*$/', $line) == 1) {
  1888.             return SMARTIRC_TYPE_QUIT;
  1889.         } else {
  1890.             $this->log(SMARTIRC_DEBUG_MESSAGETYPES, 'DEBUG_MESSAGETYPES: SMARTIRC_TYPE_UNKNOWN!: "'.$line.'"', __FILE__, __LINE__);
  1891.             return SMARTIRC_TYPE_UNKNOWN;
  1892.         }
  1893.     }
  1894.     
  1895.     /**
  1896.      * updates the current connection state
  1897.      *
  1898.      * @return boolean
  1899.      * @access private
  1900.      */
  1901.     function _updatestate()
  1902.     {
  1903.         $rtype = get_resource_type($this->_socket);
  1904.         if ((is_resource($this->_socket)) &&
  1905.             ($this->_socket !== false) &&
  1906.             ($rtype == 'socket' || $rtype == 'Socket' || $rtype == 'stream')) {
  1907.             
  1908.             $this->_state = true;
  1909.             return true;
  1910.         } else {
  1911.             $this->_state = false;
  1912.             $this->_loggedin = false;
  1913.             return false;
  1914.         }
  1915.     }
  1916.     
  1917.     /**
  1918.      * returns the current connection state
  1919.      *
  1920.      * @return integer SMARTIRC_STATE_CONNECTED or SMARTIRC_STATE_DISCONNECTED
  1921.      * @access private
  1922.      */
  1923.     function _state()
  1924.     {
  1925.         $result = $this->_updatestate();
  1926.         
  1927.         if ($result == true) {
  1928.             return SMARTIRC_STATE_CONNECTED;
  1929.         } else {
  1930.             return SMARTIRC_STATE_DISCONNECTED;
  1931.         }
  1932.     }
  1933.     
  1934.     /**
  1935.      * tries to find a messagehandler for the received message ($ircdata) and calls it
  1936.      *
  1937.      * @param string $messagecode
  1938.      * @param object $ircdata
  1939.      * @return void
  1940.      * @access private
  1941.      */
  1942.     function _handlemessage($messagecode, &$ircdata)
  1943.     {
  1944.         $found = false;
  1945.         
  1946.         if (is_numeric($messagecode)) {
  1947.             if (!array_key_exists($messagecode, $this->nreplycodes)) {
  1948.                 $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: ignoring unreconzied messagecode! "'.$messagecode.'"', __FILE__, __LINE__);
  1949.                 $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: this IRC server ('.$this->_address.') doesn\'t conform to the RFC 2812!', __FILE__, __LINE__);
  1950.                 return;
  1951.             }
  1952.             
  1953.             $methodname = 'event_'.strtolower($this->nreplycodes[$messagecode]);
  1954.             $_methodname = '_'.$methodname;
  1955.             $_codetype = 'by numeric';
  1956.         } else if (is_string($messagecode)) { // its not numericcode so already a name/string
  1957.             $methodname = 'event_'.strtolower($messagecode);
  1958.             $_methodname = '_'.$methodname;
  1959.             $_codetype = 'by string';
  1960.         }
  1961.         
  1962.         // if exists call internal method for the handling
  1963.         if (@method_exists($this, $_methodname)) {
  1964.            $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: calling internal method "'.get_class($this).'->'.$_methodname.'" ('.$_codetype.')', __FILE__, __LINE__);
  1965.            $this->$_methodname($ircdata);
  1966.            $found = true;
  1967.         }
  1968.         
  1969.         // if exist, call user defined method for the handling
  1970.         if (@method_exists($this, $methodname)) {
  1971.            $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: calling user defined method "'.get_class($this).'->'.$methodname.'" ('.$_codetype.')', __FILE__, __LINE__);
  1972.            $this->$methodname($ircdata);
  1973.            $found = true;
  1974.         }
  1975.         
  1976.         if ($found == false) {
  1977.             $this->log(SMARTIRC_DEBUG_MESSAGEHANDLER, 'DEBUG_MESSAGEHANDLER: no method found for "'.$messagecode.'" ('.$methodname.')', __FILE__, __LINE__);
  1978.         }
  1979.     }
  1980.     
  1981.     /**
  1982.      * tries to find a actionhandler for the received message ($ircdata) and calls it
  1983.      *
  1984.      * @param object $ircdata
  1985.      * @return void
  1986.      * @access private
  1987.      */
  1988.     function _handleactionhandler(&$ircdata)
  1989.     {
  1990.         $handler = &$this->_actionhandler;
  1991.         $handlercount = count($handler);
  1992.         for ($i = 0; $i < $handlercount; $i++) {
  1993.             $handlerobject = &$handler[$i];
  1994.             
  1995.             if (substr($handlerobject->message, 0, 1) == '/') {
  1996.                 $regex = $handlerobject->message;
  1997.             } else {
  1998.                 $regex = '/'.$handlerobject->message.'/';
  1999.             }
  2000.             
  2001.             if (($handlerobject->type & $ircdata->type) &&
  2002.                 (preg_match($regex, $ircdata->message) == 1)) {
  2003.                 
  2004.                 $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: actionhandler match found for id: '.$i.' type: '.$ircdata->type.' message: "'.$ircdata->message.'" regex: "'.$regex.'"', __FILE__, __LINE__);
  2005.                 
  2006.                 $methodobject = &$handlerobject->object;
  2007.                 $method = $handlerobject->method;
  2008.                 
  2009.                 if (@method_exists($methodobject, $method)) {
  2010.                     $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: calling method "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__);
  2011.                     $methodobject->$method($this, $ircdata);
  2012.                 } else {
  2013.                     $this->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: method doesn\'t exist! "'.get_class($methodobject).'->'.$method.'"', __FILE__, __LINE__);
  2014.                 }
  2015.                 
  2016.                 break;
  2017.             }
  2018.         }
  2019.     }
  2020.     
  2021.     /**
  2022.      * getting current microtime, needed for benchmarks
  2023.      *
  2024.      * @return float
  2025.      * @access private
  2026.      */
  2027.     function _microint()
  2028.     {
  2029.         $tmp = microtime();
  2030.         $parts = explode(' ', $tmp);
  2031.         $floattime = (float)$parts[0] + (float)$parts[1];
  2032.         return $floattime;
  2033.     }
  2034.     
  2035.     /**
  2036.      * adds an user to the channelobject or updates his info
  2037.      *
  2038.      * @param object $channel
  2039.      * @param object $newuser
  2040.      * @return void
  2041.      * @access private
  2042.      */
  2043.     function _adduser(&$channel, &$newuser)
  2044.     {
  2045.         $lowerednick = strtolower($newuser->nick);
  2046.         if (isset($channel->users[$lowerednick])) {
  2047.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: updating user: '.$newuser->nick.' on channel: '.$channel->name, __FILE__, __LINE__);
  2048.             
  2049.             // lets update the existing user
  2050.             $currentuser = &$channel->users[$lowerednick];
  2051.             
  2052.             if ($newuser->ident !== null) {
  2053.                 $currentuser->ident = $newuser->ident;
  2054.             }
  2055.             if ($newuser->host !== null) {
  2056.                 $currentuser->host = $newuser->host;
  2057.             }
  2058.             if ($newuser->realname !== null) {
  2059.                 $currentuser->realname = $newuser->realname;
  2060.             }
  2061.             if ($newuser->op !== null) {
  2062.                 $currentuser->op = $newuser->op;
  2063.             }
  2064.             if ($newuser->voice !== null) {
  2065.                 $currentuser->voice = $newuser->voice;
  2066.             }
  2067.             if ($newuser->ircop !== null) {
  2068.                 $currentuser->ircop = $newuser->ircop;
  2069.             }
  2070.             if ($newuser->away !== null) {
  2071.                 $currentuser->away = $newuser->away;
  2072.             }
  2073.             if ($newuser->server !== null) {
  2074.                 $currentuser->server = $newuser->server;
  2075.             }
  2076.             if ($newuser->hopcount !== null) {
  2077.                 $currentuser->hopcount = $newuser->hopcount;
  2078.             }
  2079.         } else {
  2080.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding user: '.$newuser->nick.' to channel: '.$channel->name, __FILE__, __LINE__);
  2081.             
  2082.             // he is new just add the reference to him
  2083.             $channel->users[$lowerednick] = &$newuser;
  2084.         }
  2085.         
  2086.         $user = &$channel->users[$lowerednick];
  2087.         if ($user->op) {
  2088.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding op: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__);
  2089.             $channel->ops[$user->nick] = true;
  2090.         }
  2091.         if ($user->voice) {
  2092.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: adding voice: '.$user->nick.' to channel: '.$channel->name, __FILE__, __LINE__);
  2093.             $channel->voices[$user->nick] = true;
  2094.         }
  2095.     }
  2096.     
  2097.     /**
  2098.      * removes an user from one channel or all if he quits
  2099.      *
  2100.      * @param object $ircdata
  2101.      * @return void
  2102.      * @access private
  2103.      */
  2104.     function _removeuser(&$ircdata)
  2105.     {
  2106.         if ($ircdata->type & (SMARTIRC_TYPE_PART|SMARTIRC_TYPE_QUIT)) {
  2107.             $nick = $ircdata->nick;
  2108.         } else if ($ircdata->type & SMARTIRC_TYPE_KICK) {
  2109.             $nick = $ircdata->rawmessageex[3];
  2110.         } else {
  2111.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: unknown TYPE ('.$ircdata->type.') in _removeuser(), trying default', __FILE__, __LINE__);
  2112.             $nick = $ircdata->nick;
  2113.         }
  2114.         
  2115.         $lowerednick = strtolower($nick);
  2116.         
  2117.         if ($this->_nick == $nick) {
  2118.             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: we left channel: '.$ircdata->channel.' destroying...', __FILE__, __LINE__);
  2119.             unset($this->_channels[strtolower($ircdata->channel)]);
  2120.         } else {
  2121.             if ($ircdata->type & SMARTIRC_TYPE_QUIT) {
  2122.                 $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: user '.$nick.' quit, removing him from all channels', __FILE__, __LINE__);
  2123.                 // remove the user from all channels
  2124.                 foreach ($this->_channels as $channelkey => $channelvalue) {
  2125.                     // loop through all channels
  2126.                     $channel = &$this->_channels[$channelkey];
  2127.                     foreach ($channel->users as $userkey => $uservalue) {
  2128.                         // loop through all user in this channel
  2129.                         
  2130.                         if ($nick == $uservalue->nick) {
  2131.                             // found him
  2132.                             // kill him
  2133.                             $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: found him on channel: '.$channel->name.' destroying...', __FILE__, __LINE__);
  2134.                             unset($channel->users[$lowerednick]);
  2135.                             
  2136.                             if (isset($channel->ops[$nick])) {
  2137.                                 // die!
  2138.                                 $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from op list', __FILE__, __LINE__);
  2139.                                 unset($channel->ops[$nick]);
  2140.                             }
  2141.                             
  2142.                             if (isset($channel->voices[$nick])) {
  2143.                                 // die!!
  2144.                                 $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from voice list', __FILE__, __LINE__);
  2145.                                 unset($channel->voices[$nick]);
  2146.                             }
  2147.                             
  2148.                             // ups this was not DukeNukem 3D
  2149.                         }
  2150.                     }
  2151.                 }
  2152.             } else {
  2153.                 $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing user: '.$nick.' from channel: '.$ircdata->channel, __FILE__, __LINE__);
  2154.                 $channel = &$this->_channels[strtolower($ircdata->channel)];
  2155.                 unset($channel->users[$lowerednick]);
  2156.                 
  2157.                 if (isset($channel->ops[$nick])) {
  2158.                     $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from op list', __FILE__, __LINE__);
  2159.                     unset($channel->ops[$nick]);
  2160.                 }
  2161.                 
  2162.                 if (isset($channel->voices[$nick])) {
  2163.                     $this->log(SMARTIRC_DEBUG_CHANNELSYNCING, 'DEBUG_CHANNELSYNCING: removing him from voice list', __FILE__, __LINE__);
  2164.                     unset($channel->voices[$nick]);
  2165.                 }
  2166.             }
  2167.         }
  2168.     }
  2169.     
  2170.     /**
  2171.      * @return void
  2172.      * @access private
  2173.      */
  2174.     function _checkPHPVersion()
  2175.     {
  2176.         // doing nothing at the moment
  2177.     }
  2178.     
  2179.     /**
  2180.      * checks if the passed handlertype is valid
  2181.      *
  2182.      * @param integer $handlertype
  2183.      * @return boolean
  2184.      * @access private
  2185.      */
  2186.     function _isValidType($handlertype) {
  2187.         if ($handlertype & SMARTIRC_TYPE_ALL ) {
  2188.             return true;
  2189.         } else {
  2190.             return false;
  2191.         }
  2192.     }
  2193.     
  2194.     // </private methods>
  2195.     
  2196.     function isError($object) {
  2197.         return (bool)(is_object($object) && (strtolower(get_class($object)) == 'net_smartirc_error'));
  2198.     }
  2199.     
  2200.     function &throwError($message) {
  2201.         return new Net_SmartIRC_Error($message);
  2202.     }
  2203. }
  2204.  
  2205. class Net_SmartIRC extends Net_SmartIRC_messagehandler
  2206. {
  2207.     // empty
  2208. }
  2209.  
  2210. /**
  2211.  * @access public
  2212.  */
  2213. class Net_SmartIRC_data
  2214. {
  2215.     /**
  2216.      * @var string
  2217.      * @access public
  2218.      */
  2219.     var $from;
  2220.     
  2221.     /**
  2222.      * @var string
  2223.      * @access public
  2224.      */
  2225.     var $nick;
  2226.     
  2227.     /**
  2228.      * @var string
  2229.      * @access public
  2230.      */
  2231.     var $ident;
  2232.     
  2233.     /**
  2234.      * @var string
  2235.      * @access public
  2236.      */
  2237.     var $host;
  2238.     
  2239.     /**
  2240.      * @var string
  2241.      * @access public
  2242.      */
  2243.     var $channel;
  2244.     
  2245.     /**
  2246.      * @var string
  2247.      * @access public
  2248.      */
  2249.     var $message;
  2250.     
  2251.     /**
  2252.      * @var array
  2253.      * @access public
  2254.      */
  2255.     var $messageex = array();
  2256.     
  2257.     /**
  2258.      * @var integer
  2259.      * @access public
  2260.      */
  2261.     var $type;
  2262.     
  2263.     /**
  2264.      * @var string
  2265.      * @access public
  2266.      */
  2267.     var $rawmessage;
  2268.     
  2269.     /**
  2270.      * @var array
  2271.      * @access public
  2272.      */
  2273.     var $rawmessageex = array();
  2274. }
  2275.  
  2276. /**
  2277.  * @access public
  2278.  */
  2279. class Net_SmartIRC_actionhandler
  2280. {
  2281.     /**
  2282.      * @var integer
  2283.      * @access public
  2284.      */
  2285.     var $id;
  2286.     
  2287.     /**
  2288.      * @var integer
  2289.      * @access public
  2290.      */
  2291.     var $type;
  2292.     
  2293.     /**
  2294.      * @var string
  2295.      * @access public
  2296.      */
  2297.     var $message;
  2298.     
  2299.     /**
  2300.      * @var object
  2301.      * @access public
  2302.      */
  2303.     var $object;
  2304.     
  2305.     /**
  2306.      * @var string
  2307.      * @access public
  2308.      */
  2309.     var $method;
  2310. }
  2311.  
  2312. /**
  2313.  * @access public
  2314.  */
  2315. class Net_SmartIRC_timehandler
  2316. {
  2317.     /**
  2318.      * @var integer
  2319.      * @access public
  2320.      */
  2321.     var $id;
  2322.     
  2323.     /**
  2324.      * @var integer
  2325.      * @access public
  2326.      */
  2327.     var $interval;
  2328.     
  2329.     /**
  2330.      * @var integer
  2331.      * @access public
  2332.      */
  2333.     var $lastmicrotimestamp;
  2334.     
  2335.     /**
  2336.      * @var object
  2337.      * @access public
  2338.      */
  2339.     var $object;
  2340.     
  2341.     /**
  2342.      * @var string
  2343.      * @access public
  2344.      */
  2345.     var $method;
  2346. }
  2347.  
  2348. /**
  2349.  * @access public
  2350.  */
  2351. class Net_SmartIRC_channel
  2352. {
  2353.     /**
  2354.      * @var string
  2355.      * @access public
  2356.      */
  2357.     var $name;
  2358.     
  2359.     /**
  2360.      * @var string
  2361.      * @access public
  2362.      */
  2363.     var $key;
  2364.     
  2365.     /**
  2366.      * @var array
  2367.      * @access public
  2368.      */
  2369.     var $users = array();
  2370.     
  2371.     /**
  2372.      * @var array
  2373.      * @access public
  2374.      */
  2375.     var $ops = array();
  2376.     
  2377.     /**
  2378.      * @var array
  2379.      * @access public
  2380.      */
  2381.     var $voices = array();
  2382.     
  2383.     /**
  2384.      * @var array
  2385.      * @access public
  2386.      */
  2387.     var $bans = array();
  2388.     
  2389.     /**
  2390.      * @var string
  2391.      * @access public
  2392.      */
  2393.     var $topic;
  2394.     
  2395.     /**
  2396.      * @var string
  2397.      * @access public
  2398.      */
  2399.     var $mode;
  2400. }
  2401.  
  2402. /**
  2403.  * @access public
  2404.  */
  2405. class Net_SmartIRC_user
  2406. {
  2407.     /**
  2408.      * @var string
  2409.      * @access public
  2410.      */
  2411.     var $nick;
  2412.     
  2413.     /**
  2414.      * @var string
  2415.      * @access public
  2416.      */
  2417.     var $ident;
  2418.     
  2419.     /**
  2420.      * @var string
  2421.      * @access public
  2422.      */
  2423.     var $host;
  2424.     
  2425.     /**
  2426.      * @var string
  2427.      * @access public
  2428.      */
  2429.     var $realname;
  2430.     
  2431.     /**
  2432.      * @var boolean
  2433.      * @access public
  2434.      */
  2435.     var $ircop;
  2436.     
  2437.     /**
  2438.      * @var boolean
  2439.      * @access public
  2440.      */
  2441.     var $away;
  2442.     
  2443.     /**
  2444.      * @var string
  2445.      * @access public
  2446.      */
  2447.     var $server;
  2448.     
  2449.     /**
  2450.      * @var integer
  2451.      * @access public
  2452.      */
  2453.     var $hopcount;
  2454. }
  2455.  
  2456. /**
  2457.  * @access public
  2458.  */
  2459. class Net_SmartIRC_channeluser extends Net_SmartIRC_user
  2460. {
  2461.     /**
  2462.      * @var boolean
  2463.      * @access public
  2464.      */
  2465.     var $op;
  2466.     
  2467.     /**
  2468.      * @var boolean
  2469.      * @access public
  2470.      */
  2471.     var $voice;
  2472. }
  2473.  
  2474. /**
  2475.  * @access public
  2476.  */
  2477. class Net_SmartIRC_ircuser extends Net_SmartIRC_user
  2478. {
  2479.     /**
  2480.      * @var array
  2481.      * @access public
  2482.      */
  2483.     var $joinedchannels = array();
  2484. }
  2485.  
  2486. /**
  2487.  * @access public
  2488.  */
  2489. class Net_SmartIRC_listenfor
  2490. {
  2491.     /**
  2492.      * @var array
  2493.      * @access public
  2494.      */
  2495.     var $result = array();
  2496.     
  2497.     /**
  2498.      * stores the received answer into the result array
  2499.      *
  2500.      * @param object $irc
  2501.      * @param object $ircdata
  2502.      * @return void
  2503.      */
  2504.     function handler(&$irc, &$ircdata)
  2505.     {
  2506.         $irc->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: listenfor handler called', __FILE__, __LINE__);
  2507.         $this->result[] = $ircdata->message;
  2508.         $irc->disconnect(true);
  2509.     }
  2510. }
  2511.  
  2512. // so we don't break BC!
  2513. /**
  2514.  * @access public
  2515.  */
  2516. class Net_SmartIRC_objListenFor
  2517. {
  2518.     /**
  2519.      * @var array
  2520.      * @access public
  2521.      */
  2522.     var $result = array();
  2523.     
  2524.     /**
  2525.      * stores the received answer into the result array
  2526.      *
  2527.      * @param object $irc
  2528.      * @param object $ircdata
  2529.      * @return void
  2530.      */
  2531.     function handler(&$irc, &$ircdata)
  2532.     {
  2533.         $irc->log(SMARTIRC_DEBUG_ACTIONHANDLER, 'DEBUG_ACTIONHANDLER: objListenFor handler called', __FILE__, __LINE__);
  2534.         $this->result[] = $ircdata;
  2535.         $irc->disconnect(true);
  2536.     }
  2537. }
  2538.  
  2539. class Net_SmartIRC_Error
  2540. {
  2541.     var $error_msg;
  2542.     
  2543.     function Net_SmartIRC_Error($message)
  2544.     {
  2545.         $this->error_msg = $message;
  2546.     }
  2547.     
  2548.     function getMessage()
  2549.     {
  2550.         return $this->error_msg;
  2551.     }
  2552. }
  2553. ?>